package com.example.filesynsystem.util;

import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.*;
import com.example.filesynsystem.pojo.FileData;
import com.example.filesynsystem.pojo.Interupt;
import com.example.filesynsystem.repo.InteruptRepo;
import com.sun.org.apache.xpath.internal.operations.Bool;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.persistence.Column;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Component
public class AwsFileUtil {
    @Autowired
    private AmazonS3 s3;

    //桶名称
    @Value("${s3.bucketName}")
    private String bucketName;

    //本地文件
    @Value("${s3.localPath}")
    private String localPath;

    @Resource
    private InteruptRepo interuptRepo;

    //获取桶内所有文件信息
    public List<FileData> getFileData() {
        //可以加入文件名前缀当作搜索条件
        String prefix = "";
        List<FileData> fileDatas = new ArrayList<>();
        ObjectListing objectListing = s3.listObjects(bucketName);
        List<S3ObjectSummary> s3ObjectSummaryList = objectListing.getObjectSummaries();
        s3ObjectSummaryList.forEach(item->{
            //文件路径及名称-如果是文件夹，以"/"标识路径
            System.out.println(item.getKey()+",");

            FileData fileData = new FileData();
            fileData.setId(item.getETag());
            fileData.setModifyTime(item.getLastModified());
            fileData.setKeyName(item.getKey());
            fileData.setSize(item.getSize());
            fileDatas.add(fileData);
        });
        return fileDatas;
    }

    //获取一个文件
    public S3Object getFile(String fileName) throws IOException {
        String keyName = fileName;
        //获取文件
        S3Object s3Object = s3.getObject(bucketName,keyName);

        return s3Object;
    }

    //上传新文件(如果有相同文件名则会自动覆盖
    public void uploadFile(String fileName) {
        String keyName = fileName;
        String filePath = localPath +"\\"+ fileName;
        File file = new File(filePath);

        System.out.format("Uploading %s to S3 bucket %s...\n", filePath, bucketName);
        for (int i = 0; i < 2; i++) {
            try {
                s3.putObject(bucketName, keyName, file);
                break;
            } catch (AmazonServiceException e) {
                if (e.getErrorCode().equalsIgnoreCase("NoSuchBucket")) {
                    s3.createBucket(bucketName);
                    continue;
                }

                System.err.println(e.toString());
                System.exit(1);
            } catch (AmazonClientException e) {
                try {
                    // detect bucket whether exists
                    s3.getBucketAcl(bucketName);
                } catch (AmazonServiceException ase) {
                    if (ase.getErrorCode().equalsIgnoreCase("NoSuchBucket")) {
                        s3.createBucket(bucketName);
                        continue;
                    }
                } catch (Exception ignore) {
                }

                System.err.println(e.toString());
                System.exit(1);
            }
        }
    }

    //下载新文件(如果有相同文件名则会自动覆盖
    public void downloadFile(String fileName) {
        String keyName = fileName;

        System.out.format("Downloading %s to S3 bucket %s...\n", keyName, bucketName);

        String filePath = localPath + "\\"+ fileName;

        S3ObjectInputStream s3is = null;
        FileOutputStream fos = null;
        try {
            S3Object o = s3.getObject(bucketName, keyName);
            s3is = o.getObjectContent();
            fos = new FileOutputStream(new File(filePath));
            byte[] read_buf = new byte[64 * 1024];
            int read_len = 0;
            while ((read_len = s3is.read(read_buf)) > 0) {
                fos.write(read_buf, 0, read_len);
            }
        } catch (AmazonServiceException e) {
            System.err.println(e.toString());
            System.exit(1);
        } catch (IOException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        } finally {
            if (s3is != null) try { s3is.close(); } catch (IOException e) { }
            if (fos != null) try { fos.close(); } catch (IOException e) { }
        }

        System.out.println("Done!");
    }

    //上传超出20M的大文件
    public void uploadBigFile(String fileName) {
        String keyName = fileName;

        String filePath = localPath + "\\"+fileName;

        File file = new File(filePath);
        long contentLength = file.length();
        String uploadId = null;
        ArrayList<PartETag> partETags = new ArrayList<PartETag>();
        long partSize = 5 << 20;

        try {
            // Step 1: Initialize.
            InitiateMultipartUploadRequest initRequest =
                    new InitiateMultipartUploadRequest(bucketName, keyName);
            uploadId = s3.initiateMultipartUpload(initRequest).getUploadId();
            System.out.format("Created upload ID was %s\n", uploadId);

            // Step 2: Upload parts.
            long filePosition = 0;

            List<Interupt> interuptList = interuptRepo.findAllByFileName(keyName);
            //记录上一个filePosition的位置
            Long lastFilePosition = 0L;
            if (interuptList.size() != 0) {
                filePosition = interuptList.get(0).getFilePosition();
            }

            for (int i = 1; filePosition < contentLength; i++) {
                // Last part can be less than 5 MB. Adjust part size.
                partSize = Math.min(partSize, contentLength - filePosition);

                // Create request to upload a part.
                UploadPartRequest uploadRequest = new UploadPartRequest()
                        .withBucketName(bucketName)
                        .withKey(keyName)
                        .withUploadId(uploadId)
                        .withPartNumber(i)
                        .withFileOffset(filePosition)
                        .withFile(file)
                        .withPartSize(partSize);

                // Upload part and add response to our list.
                System.out.format("Uploading part %d\n", i);
                partETags.add(s3.uploadPart(uploadRequest).getPartETag());

                filePosition += partSize;
                Interupt interupt = new Interupt();
                interupt.setStatus(1);
                interupt.setFilePosition(filePosition);
                interupt.setFileName(keyName);
                interuptRepo.save(interupt);
                interuptRepo.deleteInteruptByFilePositionAndFileName(lastFilePosition,keyName);
                lastFilePosition = filePosition;
            }

            // Step 3: Complete.
            System.out.println("Completing upload");
            CompleteMultipartUploadRequest compRequest =
                    new CompleteMultipartUploadRequest(bucketName, keyName, uploadId, partETags);
            s3.completeMultipartUpload(compRequest);
            interuptRepo.deleteInteruptByFilePositionAndFileName(lastFilePosition,keyName);
        } catch (Exception e) {
            System.err.println(e.toString());
            if (uploadId != null && !uploadId.isEmpty()) {
                // Cancel when error occurred
                System.out.println("Aborting upload");
                s3.abortMultipartUpload(new AbortMultipartUploadRequest(bucketName, keyName, uploadId));
            }
            System.exit(1);
        }
        System.out.println("Done!");
    }

    //下载超出20M的大文件
    public void downloadBigFile(String fileName) {
        String keyName = fileName;
        String filePath = localPath + "\\" + fileName;
        File file = new File(filePath);
        long partSize = 5 << 20;
        S3Object o = null;

        S3ObjectInputStream s3is = null;
        FileOutputStream fos = null;

        //新建一个用例
        Interupt interupt = new Interupt();

        try {
            // Step 1: Initialize.
            ObjectMetadata oMetaData = s3.getObjectMetadata(bucketName, keyName);
            final long contentLength = oMetaData.getContentLength();
            final GetObjectRequest downloadRequest =
                    new GetObjectRequest(bucketName, keyName);

            fos = new FileOutputStream(file);

            // Step 2: Download parts.
            long filePosition = 0;

            for (int i = 1; filePosition < contentLength; i++) {
                // Last part can be less than 5 MB. Adjust part size.
                partSize = Math.min(partSize, contentLength - filePosition);

                // Create request to download a part.
                downloadRequest.setRange(filePosition, filePosition + partSize);
                o = s3.getObject(downloadRequest);

                // download part and save to local file.
                System.out.format("Downloading part %d\n", i);

                filePosition += partSize+1;
                s3is = o.getObjectContent();
                byte[] read_buf = new byte[64 * 1024];
                int read_len = 0;
                while ((read_len = s3is.read(read_buf)) > 0) {
                    fos.write(read_buf, 0, read_len);
                }
//                interupt.setFilePosition(filePosition);
//                interupt.setFileName(keyName);
//                interupt.setStatus(1);
//                interuptRepo.save(interupt);
//                //删除上一个位置和文件名
//                interuptRepo.deleteInteruptByFilePositionAndFileName(lastFilePosition,keyName);
//                //记录旧位置
//                lastFilePosition = filePosition;
            }

            // Step 3: Complete.
            System.out.println("Completing download");
            System.out.format("save %s to %s\n", keyName, filePath);
//            interuptRepo.deleteInteruptByFilePositionAndFileName(lastFilePosition,keyName);
        } catch (Exception e) {
            System.err.println(e.toString());

            System.exit(1);
        } finally {
            if (s3is != null) try { s3is.close(); } catch (IOException e) { }
            if (fos != null) try { fos.close(); } catch (IOException e) { }
        }
        System.out.println("Done!");
    }

    //删除文件
    public void deleteFile(String fileName) {
        s3.deleteObject(bucketName,fileName);
    }
}
